`include "defines.v"
`timescale 1ns / 1ns
module ex(
    input clk,
    input rst,

    // from id 
    input wire[`InstBus] inst_i,
    input wire[`InstAddrBus] InstAddr_i,
    input wire[`RegBus] rdata1_i,
    input wire[`RegBus] rdata2_i,
    input wire[`RegBus] rdata_csr_i, //csr_reg

    //from memory
    input wire[`MemBus] mrdata_i,

    //from clint
    input wire[`InstAddrBus] int_addr_clint_i,     // 中断入口地址
    input  wire int_assert_clint_i,

    // to clint 
    output wire jump_flag_clint_o,
    output wire[`InstAddrBus] jump_addr_clint_o,

    // to csr_reg
    output reg we_csr_o,                             
    output reg[`MemAddrBus] waddr_csr_o,        
    output reg[`RegBus] data_csr_o,  

    // to ctrl
    output wire jump_flag_o,
    output wire[`InstAddrBus] jump_addr_o,
    output reg hold_flag_o,//the if and id module should be empty,when there is a jump

    //to reg
    output reg[`RegAddrBus] waddr_o,
    output reg we_o,
    output reg[`RegBus] wdata_o,

    //to memory
    output reg[`MemAddrBus] mraddr_o,
    output reg[`MemAddrBus] mwaddr_o,
    output reg[`MemBus] mwdata_o,
    output reg mwe_o

);
    wire[6:0] opcode = inst_i[6:0];
    wire[2:0] funct3 = inst_i[14:12];
    wire[6:0] funct7 = inst_i[31:25];
    wire[4:0] rd = inst_i[11:7];
    wire[4:0] rs1 = inst_i[19:15];
    wire[4:0] rs2 = inst_i[24:20];
    wire[4:0] zimm;


    wire[31:0] sign_extend_tmp;
    wire[4:0] shamt;
    reg jump_flag;
    reg[`InstAddrBus] jump_addr;

    wire[31:0] csr_addr = {21'b0, inst_i[31:21]};

    assign zimm = rs1;
    //wire[63:0] product;
    assign shamt = inst_i[24:20];
    assign sign_extend_tmp = {{20{inst_i[31]}}, inst_i[31:20]};

    //to ctrl 
    assign jump_addr_o = (int_assert_clint_i == `INT_ASSERT) ? int_addr_clint_i:jump_addr;
    assign jump_flag_o = (int_assert_clint_i == `INT_ASSERT) ? `JumpEnable:jump_flag;

    //to clint
    assign jump_flag_clint_o = jump_flag;
    assign jump_addr_clint_o = jump_addr;



    always @ (*)
        begin
            if (rst == `RstEnable)
                begin
                    jump_flag = `JumpDisable;
                    jump_addr = `ZeroWord;
                    hold_flag_o = `HoldDisable;

                    waddr_o = `ZeroReg;
                    we_o = `WriteDisable;
                    wdata_o = `ZeroWord;

                    mraddr_o = `ZeroWord;
                    mwaddr_o = `ZeroWord;
                    mwdata_o = `ZeroWord;
                    mwe_o = `WriteDisable;

                    data_csr_o = `ZeroWord;

                end 
            else
                begin
                    case(opcode)
                        
                        `INST_TYPE_I:
                            begin
                                //to memory
                                mraddr_o = `ZeroWord;
                                mwaddr_o = `ZeroWord;
                                mwdata_o = `ZeroWord;
                                mwe_o = `WriteDisable;

                                //to clint
                                jump_flag = `JumpDisable;
                                jump_addr = `ZeroWord;

                                //to ctrl
                                hold_flag_o = `HoldDisable;
                                //to reg
                                waddr_o = rd;
                                we_o = `WriteEnable;

                                we_csr_o = `WriteDisable;                            
                                waddr_csr_o = `ZeroWord;        
                                data_csr_o = `ZeroWord;
                                case(funct3)
                                    `INST_ADDI:
                                        begin
                                            wdata_o = rdata1_i + sign_extend_tmp; 
                                            //$display("INST_ADDI");
                                        end
                                    `INST_SLTI:
                                            begin
                                                //$display("INST_SLTI");
                                                case ({rdata1_i[31], sign_extend_tmp[31]})
                                                    2'b11: begin
                                                        if (rdata1_i < sign_extend_tmp) begin
                                                            wdata_o = 32'h00000001;
                                                        end else begin
                                                            wdata_o = 32'h00000000;
                                                        end
                                                    end
                                                    2'b10: begin
                                                        wdata_o = 32'h00000001;
                                                    end
                                                    2'b01: begin
                                                        wdata_o = 32'h00000000;
                                                    end
                                                    default: begin
                                                        if (rdata1_i < sign_extend_tmp) begin
                                                            wdata_o = 32'h00000001;
                                                        end else begin
                                                            wdata_o = 32'h00000000;
                                                        end
                                                    end
                                            endcase
                                        end
                                    `INST_SLTIU:
                                        begin
                                            //$display("INST_SLTIU");
                                            case({rdata1_i[31], sign_extend_tmp[31]})
                                                2'b11:
                                                    begin
                                                        wdata_o = (rdata1_i < sign_extend_tmp)? 32'h0000_0001:32'h0000_0000;
                                                    end
                                                2'b10:
                                                    begin
                                                        wdata_o = 32'h0000_0000;
                                                    end
                                                2'b01:
                                                    begin
                                                        wdata_o = 32'h0000_0001;
                                                    end
                                                default:
                                                    begin
                                                        wdata_o = (rdata1_i < sign_extend_tmp)? 32'h0000_0001:32'h0000_0000;
                                                    end
                                            endcase
                                         end
                                    `INST_XORI:
                                        begin
                                            //$display("INST_XORI");
                                            wdata_o = (rdata1_i ^ sign_extend_tmp) ;
                                        end
                                    `INST_ORI: 
                                        begin
                                            //$display("INST_ORI");
                                            wdata_o = (rdata1_i | sign_extend_tmp) ;
                                        end
                                    `INST_ANDI:
                                        begin
                                            //$display("INST_ANDI");
                                            wdata_o = (rdata1_i & sign_extend_tmp) ;
                                        end
                                    `INST_SLLI:
                                        begin
                                            //$display("INST_SLLI");
                                            wdata_o = (rdata1_i << shamt) ;//?? when using verilog, there is a big difference between << and <<<
                                        end
                                    `INST_SRI:
                                        begin
                                            //$display("INST_SRI");
                                        if(inst_i[30] == 1'b1)
                                            begin
                                                wdata_o = ({32{rdata1_i[31]}} << (6'd32 - {1'b0, shamt})) | (rdata1_i >> shamt);
                                            end
                                        else
                                            begin
                                                wdata_o = (rdata1_i >> shamt) ;
                                            end
                                        end
                                endcase
                            end
                        `INST_TYPE_L:
                            begin
                                mraddr_o = rdata1_i + sign_extend_tmp;
                                mwaddr_o = `ZeroWord;
                                mwdata_o = `ZeroWord;
                                mwe_o = `WriteDisable;

                               
                                //to clint
                                jump_flag = `JumpDisable;
                                jump_addr = `ZeroWord;
                                hold_flag_o = `HoldDisable;

                                waddr_o = rd;
                                we_o = `WriteEnable;
                                we_csr_o = `WriteDisable;                            
                                waddr_csr_o = `ZeroWord;        
                                data_csr_o = `ZeroWord;
                                case(funct3)
                                `INST_LB:
                                    begin
                                        //$display("INST_LB");
                                        case(mraddr_o[1:0])
                                            2'b00:
                                                begin
                                                    wdata_o = {{24{mrdata_i[7]}}, mrdata_i[7:0]};
                                                end
                                            2'b01:
                                                begin
                                                    wdata_o = {{24{mrdata_i[15]}}, mrdata_i[15:8]};
                                                end
                                            2'b10:
                                                begin
                                                    wdata_o = {{24{mrdata_i[23]}}, mrdata_i[23:16]};
                                                end
                                            2'b11:
                                                begin
                                                    wdata_o = {{24{mrdata_i[31]}}, mrdata_i[31:24]};
                                                end
                                        endcase
                                    end
                                `INST_LH:
                                    begin
                                        //$display("INST_LH");
                                        if (mraddr_o[1] == 1'b0) begin
                                            wdata_o = {{16{mrdata_i[15]}}, mrdata_i[15:0]};
                                        end else begin
                                            wdata_o = {{16{mrdata_i[31]}}, mrdata_i[31:16]};
                                        end
                                    end 
                                    
                                `INST_LW:
                                    begin
                                        //$display("INST_LW");
                                        wdata_o = mrdata_i;
                                    end
                                `INST_LBU:
                                    begin
                                        //$display("INST_LBU");
                                        case(mraddr_o[1:0])
                                            2'b00:
                                                begin
                                                    wdata_o = {24'h0, mrdata_i[7:0]};
                                                end
                                            2'b01:
                                                begin
                                                    wdata_o = {24'h0, mrdata_i[15:8]};
                                                end
                                            2'b10:
                                                begin
                                                    wdata_o = {24'h0, mrdata_i[23:16]};
                                                end
                                            2'b11:
                                                begin
                                                    wdata_o = {24'h0, mrdata_i[31:24]};
                                                end
                                        endcase
                                    end 
                                `INST_LHU:
                                    begin
                                        //$display("INST_LHU");
                                        if (mraddr_o[1] == 1'b0) begin
                                            wdata_o = {16'h0, mrdata_i[15:0]};
                                        end else begin
                                            wdata_o = {16'h0, mrdata_i[31:16]};
                                        end
                                    end
                                default:
                                    begin
                                        //$display("INST_L");
                                        we_o = `WriteDisable;
                                        wdata_o = `ZeroWord;
                                    end
                                endcase
                            end
                        `INST_TYPE_S:
                            begin
                                mraddr_o = rdata1_i + {{24{inst_i[31]}},inst_i[31:25], inst_i[11:7]};
                                mwaddr_o = rdata1_i + {{24{inst_i[31]}},inst_i[31:25], inst_i[11:7]};
                                mwe_o = `WriteEnable;


                                hold_flag_o = `HoldDisable;

                                //to clint
                                
                                jump_flag = `JumpDisable;
                                jump_addr = `ZeroWord;

                                waddr_o = `ZeroWord;
                                we_o = `WriteDisable;
                                wdata_o = `ZeroWord;
                                we_csr_o = `WriteDisable;                            
                                waddr_csr_o = `ZeroWord;        
                                data_csr_o = `ZeroWord;
                                
                                case(funct3) 
                                `INST_SB:
                                    begin
                                        //$display("INST_SB");
                                        case (mwaddr_o[1:0])
                                        2'b00: begin
                                            mwdata_o = {mrdata_i[31:8], rdata2_i[7:0]};
                                        end
                                        2'b01: begin
                                            mwdata_o = {mrdata_i[31:16], rdata2_i[7:0], mrdata_i[7:0]};
                                        end
                                        2'b10: begin
                                            mwdata_o = {mrdata_i[31:24], rdata2_i[7:0], mrdata_i[15:0]};
                                        end
                                        default: begin
                                            mwdata_o = {rdata2_i[7:0], mrdata_i[23:0]};
                                        end
                                        endcase
                                    end
                                `INST_SH:
                                    begin
                                        //$display("INST_SH");
                                        case (mwaddr_o[1])
                                        1'b0: begin
                                            mwdata_o = {mrdata_i[31:16], rdata2_i[15:0]};
                                            
                                        end
                                        1'b1: begin
                                            mwdata_o = {rdata2_i[15:0], mrdata_i[15:0]};
                                            
                                            end
                                        endcase
                                    end
                                `INST_SW:
                                    begin
                                        //$display("INST_SW");
                                        mwdata_o =  rdata2_i[31:0];
                                    end
                                default:
                                    begin
                                        //$display("INST_S");
                                        mwe_o = `WriteDisable;
                                        mwdata_o =`ZeroWord;
                                    end
                                endcase
                            end
                        `INST_TYPE_R_M:
                            begin
                                if (funct7 == 7'b0100_000 || funct7 == 7'b0000_000)
                                    begin
                                        mraddr_o = `ZeroWord;
                                        mwaddr_o = `ZeroWord;
                                        mwdata_o = `ZeroWord;
                                        mwe_o = `WriteDisable;

                                        //to clint
                                        jump_flag = `JumpDisable;
                                        jump_addr = `ZeroWord;
                                        hold_flag_o = `HoldDisable;

                                        

                                        waddr_o = rd;
                                        we_o = `WriteEnable;
                                        we_csr_o = `WriteDisable;                            
                                        waddr_csr_o = `ZeroWord;        
                                        data_csr_o = `ZeroWord;
                                        case(funct3)
                                        `INST_ADD_SUB:
                                            begin
                                                //$display("INST_ADD_SUB");
                                                if (inst_i[30] == 1'b1)
                                                    begin
                                                        wdata_o = rdata1_i - rdata2_i;
                                                    end
                                                else
                                                    begin
                                                        wdata_o = rdata1_i + rdata2_i;
                                                    end
                                            end
                                        `INST_SLL:
                                            begin
                                                //$display("INST_SLL");
                                                wdata_o = (rdata1_i << rdata2_i[4:0]);
                                            end
                                        `INST_SLT:
                                            begin
                                                //$display("INST_SLT");
                                                        case ({rdata1_i[31], rdata2_i[31]})
                                                            2'b11: begin
                                                                if (rdata1_i < rdata2_i) begin
                                                                    wdata_o = 32'h00000001;
                                                                end else begin
                                                                    wdata_o = 32'h00000000;
                                                                end
                                                            end
                                                            2'b10: begin
                                                                wdata_o = 32'h00000001;
                                                            end
                                                            2'b01: begin
                                                                wdata_o = 32'h00000000;
                                                            end
                                                            default: begin
                                                                if (rdata1_i < rdata2_i) begin
                                                                    wdata_o = 32'h00000001;
                                                                end else begin
                                                                    wdata_o = 32'h00000000;
                                                                end
                                                            end
                                                    endcase
                                                end
                                        `INST_SLTU:
                                            begin
                                                //$display("INST_SLTU");
                                                case({rdata1_i[31], rdata2_i[31]})
                                                    2'b11:
                                                    begin
                                                        wdata_o = (rdata1_i < rdata2_i)? 32'h0000_0001:32'h0000_0000;
                                                    end
                                                    2'b10:
                                                        begin
                                                            wdata_o = 32'h0000_0000;
                                                        end
                                                    2'b01:
                                                    begin
                                                    wdata_o = 32'h0000_0001;
                                                    end
                                                    2'b00:
                                                    begin
                                                        wdata_o = (rdata1_i < rdata2_i)? 32'h0000_0001:32'h0000_0000;
                                                    end
                                                endcase
                                            end
                                        `INST_XOR:
                                            begin
                                                //$display("INST_XORI");
                                                wdata_o = rdata1_i ^ rdata2_i;
                                            end
                                        `INST_SRI:
                                            begin
                                                //$display("INST_SRI");
                                                if (inst_i[30] == 1'b1)
                                                begin
                                                    wdata_o = ({32{rdata1_i[31]}} << (6'd32 - {1'b0, rdata2_i[4:0]})) | (rdata1_i >> rdata2_i[4:0]);
                                                end
                                                else
                                                begin
                                                    wdata_o = rdata1_i >> rdata2_i[4:0];
                                                end
                                            end
                                        `INST_OR:
                                            begin
                                                //$display("INST_OR");
                                                wdata_o = rdata1_i | rdata2_i;
                                            end
                                        `INST_AND:
                                            begin
                                                //$display("INST_AND");
                                                wdata_o = rdata1_i & rdata2_i;
                                            end
                                    
                                        endcase
                                    end
                                else if (funct7 == 7'b0000_001)
                                    begin
                                        mraddr_o = `ZeroWord;
                                        mwaddr_o = `ZeroWord;
                                        mwdata_o = `ZeroWord;
                                        mwe_o = `WriteDisable;

                                        jump_flag = `JumpDisable;
                                        jump_addr = `ZeroWord;
                                        hold_flag_o = `HoldDisable;

                                        waddr_o = rd;
                                        we_o = `WriteDisable;
                                        //product = rdata1_i * rdata2_i ;
                                        /*case (funct3)
                                        `INST_MUL:
                                        begin
                                            wdata_o = product[31:0];
                                        end
                                         `INST_MULH:
                                            begin
                                                wdata_o = product[63:32];
                                            end
                                          `INST_MULHSU: `INST_MULHU,`INST_DIV,`INST_DIVU,`INST_REM, `INST_REMU:
                                            begin
                                               wdata_o = (rdata1_i << rdata2_i[4:0]);
                                            end
                                        default:
                                            begin
                                                raddr1_o = `ZeroReg;
                                                raddr2_o = `ZeroReg;
                                            end
                                        endcase*/
                                    end
                            end
                        `INST_JAL:
                            begin
                                //$display("INST_JAL");
                                mraddr_o = `ZeroWord;
                                mwaddr_o = `ZeroWord;
                                mwdata_o = `ZeroWord;
                                mwe_o = `WriteDisable;

                                jump_flag = `JumpEnable;
                                jump_addr = InstAddr_i + {{12{inst_i[31]}}, inst_i[19:12], inst_i[20], inst_i[30:21], 1'b0};
                                
                                hold_flag_o = `Hold_Id;

                                waddr_o = rd;
                                wdata_o = InstAddr_i + 32'h0000_0004;
                                we_o = `WriteEnable;
                                we_csr_o = `WriteDisable;                            
                                waddr_csr_o = `ZeroWord;        
                                data_csr_o = `ZeroWord;
                            end
                        `INST_JALR:
                            begin
                                //$display("INST_JALR");
                                mraddr_o = `ZeroWord;
                                mwaddr_o = `ZeroWord;
                                mwdata_o = `ZeroWord;
                                mwe_o = `WriteDisable;

                                jump_flag = `JumpEnable;
                                jump_addr = (rdata1_i + {{20{inst_i[31]}}, inst_i[31:20]}) & (32'hffff_fffc);
                                hold_flag_o = `Hold_Id;


                                
                                waddr_o = rd;
                                wdata_o = InstAddr_i + 32'h0000_0004;
                                we_o = `WriteEnable;
                                we_csr_o = `WriteDisable;                            
                                waddr_csr_o = `ZeroWord;        
                                data_csr_o = `ZeroWord;
                            end
                        `INST_TYPE_B:
                            begin
                                mraddr_o = `ZeroWord;
                                mwaddr_o = `ZeroWord;
                                mwdata_o = `ZeroWord;
                                mwe_o = `WriteDisable;
                                
                                jump_addr = InstAddr_i + {{20{inst_i[31]}}, inst_i[7], inst_i[30:25], inst_i[11:8], 1'b0};


                                waddr_o = `ZeroReg;
                                wdata_o = `ZeroWord;
                                we_o = `WriteDisable;
                                we_csr_o = `WriteDisable;                            
                                waddr_csr_o = `ZeroWord;        
                                data_csr_o = `ZeroWord;
                                case(funct3)
                                `INST_BEQ:
                                begin
                                    //$display("INST_BEQ");
                                    if (rdata1_i == rdata2_i)
                                        begin
                                        jump_flag = `JumpEnable;
                                        hold_flag_o = `Hold_Id;
                                        end
                                    else
                                        begin
                                        jump_flag = `JumpDisable;
                                        hold_flag_o = `Hold_None;
                                        end
                                end
                                `INST_BNE:
                                begin
                                    //$display("INST_BNQ");
                                    if (rdata1_i != rdata2_i)
                                    begin
                                        jump_flag = `JumpEnable;
                                        hold_flag_o = `Hold_Id;
                                    end
                                    else
                                    begin
                                        jump_flag = `JumpDisable;
                                        hold_flag_o = `Hold_None;
                                    end
                                end
                                `INST_BLT:
                                begin
                                    //$display("INST_BLT");
                                    if (rdata1_i < rdata2_i)
                                    begin
                                        jump_flag = `JumpEnable;
                                        hold_flag_o = `Hold_Id;
                                    end
                                    else
                                    begin
                                        jump_flag = `JumpDisable;
                                        hold_flag_o = `Hold_None;
                                    end
                                end
                                `INST_BGE:
                                begin
                                    //$display("INST_BGE");
                                    if (rdata1_i > rdata2_i)
                                    begin
                                        jump_flag = `JumpEnable;
                                        hold_flag_o = `Hold_Id;
                                    end
                                    else
                                    begin
                                        jump_flag = `JumpDisable;
                                        hold_flag_o = `Hold_None;
                                    end
                                end
                                `INST_BLTU:
                                begin
                                    //$display("INST_BLTU");
                                        case({rdata1_i[31], rdata2_i[31]})
                                            2'b11:
                                            begin
                                                if (rdata1_i < rdata2_i)
                                                begin
                                                    jump_flag = `JumpEnable;
                                                    hold_flag_o = `Hold_Id;
                                                end
                                                else
                                                begin
                                                    jump_flag = `JumpDisable;
                                                    hold_flag_o = `Hold_None;
                                                end
                                    
                                            end
                                            2'b10:
                                            begin
                                                jump_flag = `JumpDisable;
                                                hold_flag_o = `Hold_None;
                                            end
                                            2'b01:
                                            begin
                                               jump_flag = `JumpEnable;
                                                hold_flag_o = `Hold_Id;
                                            end
                                            2'b00:
                                            begin
                                                if (rdata1_i < rdata2_i)
                                                begin
                                                    jump_flag = `JumpEnable;
                                                    hold_flag_o = `Hold_Id;
                                                end
                                                else
                                                begin
                                                    jump_flag = `JumpDisable;
                                                    hold_flag_o = `Hold_None;
                                                end
                                    
                                            end
                                        endcase
                                end
                                `INST_BGEU:
                                begin
                                    //$display("INST_BGEU");
                                        case({rdata1_i[31], rdata2_i[31]})
                                            2'b11:
                                            begin
                                                if (rdata1_i > rdata2_i)
                                                begin
                                                    jump_flag = `JumpEnable;
                                                    hold_flag_o = `Hold_Id;
                                                end
                                                else
                                                begin
                                                    jump_flag = `JumpDisable;
                                                    hold_flag_o = `Hold_None;
                                                end
                                    
                                            end
                                            2'b01:
                                            begin
                                                jump_flag = `JumpDisable;
                                                hold_flag_o = `Hold_None;
                                            end
                                            2'b10:
                                            begin
                                               jump_flag = `JumpEnable;
                                                hold_flag_o = `Hold_Id;
                                            end
                                            default:
                                            begin
                                                if (rdata1_i > rdata2_i)
                                                begin
                                                    jump_flag = `JumpEnable;
                                                    hold_flag_o = `Hold_Id;
                                                end
                                                else
                                                begin
                                                    jump_flag = `JumpDisable;
                                                    hold_flag_o = `Hold_None;
                                                end
                                    
                                            end
                                        endcase//end of INST_BGEU
                                
                                end
                                default:
                                    begin
                                        //$display("INST_B");
                                        jump_flag = `JumpDisable;
                                        hold_flag_o = `Hold_None;
                                    end

                                endcase//endcase of type_B
                            end//end of TypeB
                        
                        `INST_LUI:
                            begin
                                //$display("INST_LUI");
                                jump_flag = `JumpDisable;
                                jump_addr = `ZeroWord;
                                hold_flag_o = `HoldDisable;

                                waddr_o = rd;
                                we_o = `WriteEnable;
                                wdata_o = {inst_i[31:12], 12'b0};

                                mraddr_o = `ZeroWord;
                                mwaddr_o = `ZeroWord;
                                mwdata_o = `ZeroWord;
                                mwe_o = `WriteDisable;
                                we_csr_o = `WriteDisable;                            
                                waddr_csr_o = `ZeroWord;        
                                data_csr_o = `ZeroWord;
                            end
                        `INST_AUIPC:
                            begin
                                //$display("INST_AUIPC");
                                jump_flag = `JumpDisable;
                                jump_addr = `ZeroWord;
                                hold_flag_o = `HoldDisable;

                                waddr_o = rd;
                                we_o = `WriteEnable;
                                wdata_o = {inst_i[31:12], 12'b0} + InstAddr_i;

                                mraddr_o = `ZeroWord;
                                mwaddr_o = `ZeroWord;
                                mwdata_o = `ZeroWord;
                                mwe_o = `WriteDisable;
                                we_csr_o = `WriteDisable;                            
                                waddr_csr_o = `ZeroWord;        
                                data_csr_o = `ZeroWord;
                                
                            end
                        `INST_CSR:
                            begin
                                jump_flag = `JumpDisable;
                                jump_addr = `ZeroWord;
                                hold_flag_o = `HoldDisable;

                                waddr_o = rd;
                                we_o = `WriteEnable;
                                //wdata_o = `ZeroWord;
                                mraddr_o = `ZeroWord;
                                mwaddr_o = `ZeroWord;
                                mwdata_o = `ZeroWord;
                                mwe_o = `WriteDisable;

                                                            
                                waddr_csr_o = csr_addr;        
                                //data_csr_o = `ZeroWord;

                                case(funct3)
                                `INST_CSRRW:begin
                                    we_csr_o = `WriteEnable;
                                    wdata_o = rdata_csr_i;
                                    data_csr_o = rdata1_i;
                                end
                                `INST_CSRRS:begin
                                    we_csr_o = `WriteEnable;
                                    wdata_o = rdata_csr_i;
                                    data_csr_o = (rdata1_i | rdata_csr_i);
                                end
                                `INST_CSRRC:begin
                                    we_csr_o = `WriteEnable;
                                    wdata_o = rdata_csr_i;
                                    data_csr_o = (~rdata1_i & rdata_csr_i);
                                end
                                `INST_CSRRWI:begin
                                    we_csr_o = `WriteEnable;
                                    wdata_o = rdata_csr_i;
                                    data_csr_o = {27'b0, rs1};//rs1 is equal to zimm
                                end
                                `INST_CSRRSI:begin
                                    we_csr_o = `WriteEnable;
                                    wdata_o = rdata_csr_i;
                                    data_csr_o = (~{27'b0, zimm} | rdata_csr_i);
                                end
                                `INST_CSRRCI:begin
                                    we_csr_o = `WriteEnable;
                                    wdata_o = rdata_csr_i;
                                    data_csr_o = (~{27'b0, zimm} & rdata_csr_i);
                                end
                                default:begin
                                    we_csr_o = `WriteDisable;
                                    wdata_o = rdata_csr_i;
                                    data_csr_o = (~{27'b0, zimm} & rdata_csr_i);
                                end
                                endcase
                            end
                        //`INST_FENCE://to instruction wasn't get into reality
                        `INST_NOP_OP:
                            begin
                                //$display("INST_NOP");
                                    jump_flag = `JumpDisable;
                                    jump_addr = `ZeroWord;
                                    hold_flag_o = `HoldDisable;
                                    waddr_o = `ZeroReg;
                                    we_o = `WriteDisable;
                                    wdata_o = `ZeroWord;
                                    mraddr_o = `ZeroWord;
                                    mwaddr_o = `ZeroWord;
                                    mwdata_o = `ZeroWord;
                                    mwe_o = `WriteDisable;
                                    we_csr_o = `WriteDisable;                            
                                    waddr_csr_o = `ZeroWord;        
                                    data_csr_o = `ZeroWord;
                            end
                        default:
                            begin
                                    jump_flag = `JumpDisable;
                                    jump_addr = `ZeroWord;
                                    hold_flag_o = `HoldDisable;
                                    waddr_o = `ZeroReg;
                                    we_o = `WriteDisable;
                                    wdata_o = `ZeroWord;
                                    mraddr_o = `ZeroWord;
                                    mwaddr_o = `ZeroWord;
                                    mwdata_o = `ZeroWord;
                                    mwe_o = `WriteDisable;
                                    we_csr_o = `WriteDisable;                            
                                    waddr_csr_o = `ZeroWord;        
                                    data_csr_o = `ZeroWord;
                            end

                    endcase//end of tupe distinction
                end
        end
endmodule
